package com.ylg.mybatis.core;

import com.ylg.mybatis.utils.Resource;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import javax.sql.DataSource;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @since 1.0
 * @author 杨凌广
 * @version 1.0
 *
 * SqlSessionFactoryBuilder对象 ,负责创建SqlSessionFactory对象
  */
public class SqlSessionFactoryBuilder {

    /**
     * 创建SqlSessionFactory对象
     * 通过读取配置文件 封装对象
     * @param in
     * @return
     */
    public SqlSessionFactory build(InputStream in) {

        SqlSessionFactory sqlSessionFactory = null;

        try {

            SAXReader saxReader = new SAXReader();
            Document read = saxReader.read(in);
            Element element = (Element) read.selectSingleNode("/configuration/environments");
            String defaultId = element.attributeValue("default");
            Element environment = (Element) element.selectSingleNode("environment[@id='" + defaultId + "']");
            Element transactionManagerEle = (Element) environment.selectSingleNode("transactionManager");
            Element dataSourceEle = (Element) environment.selectSingleNode("dataSource");
            // 创建数据源对象
            DataSource dataSource = getDataSource(dataSourceEle);
            // 创建事务管理器对象
            Transaction transaction = getTransaction(transactionManagerEle, dataSource);
            // 创建mapper文件对应的map对象
            // 先从主配置文件中获取mapper标签对应mapper映射文件的路径
            List<Node> mappers = read.selectNodes("//mapper");
            List<String> resources = mappers.stream().map(mapper -> {
                Element mapperEle = (Element) mapper;
                return mapperEle.attributeValue("resource");
            }).collect(Collectors.toList());
            Map<String, MappedStatement> mappedStatements = getMappedStatement(resources);
            sqlSessionFactory = new SqlSessionFactory(transaction, mappedStatements);
        } catch (Exception e) {
            e.printStackTrace();

        }

        return sqlSessionFactory;
    }

    /**
     * 创建mapper文件对应的sql标签的集合
     * @param resources
     * @return
     */
    private Map<String, MappedStatement> getMappedStatement(List<String> resources) {
        Map<String, MappedStatement> mappedStatements = new HashMap<>();
        resources.forEach(resource -> {
            try {
                InputStream inputStream = Resource.getResourceAsStream(resource);
                SAXReader saxReader = new SAXReader();
                Document read = saxReader.read(inputStream);
                Element mapperElement = (Element) read.selectSingleNode("/mapper");
                String namespace = mapperElement.attributeValue("namespace");
                List<Element> elements = mapperElement.elements();
                elements.forEach(element -> {
                    String id = element.attributeValue("id");
                    String sqlId = namespace + "." + id;
                    String sql = element.getTextTrim();
                    String resultType = element.attributeValue("resultType");
                    String name = element.getName();
                    MappedStatement mappedStatement = new MappedStatement(sql, resultType, name);
                    mappedStatements.put(sqlId, mappedStatement);
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        return mappedStatements;
    }

    /**
     * 创建事务管理器对象
     * @param transactionManagerEle
     * @param dataSource
     * @return
     */
    private Transaction getTransaction(Element transactionManagerEle, DataSource dataSource) {
        Transaction transaction = null;
        String type = transactionManagerEle.attributeValue("type");
        if (Const.JDBC_TRANSACTION.equals(type.trim().toUpperCase())) {
            // 默认开启事务
            transaction = new JdbcTransaction(dataSource, false);
        }
        return transaction;
    }

    /**
     * 创建数据源对象
     * @param dataSourceEle
     * @return
     */
    private DataSource getDataSource(Element dataSourceEle) {
        DataSource dataSource = null;
        String type = dataSourceEle.attributeValue("type");
        // 读取配置文件中的数据库信息
        List<Node> property = dataSourceEle.selectNodes("property");
        Map<String, String> properties = property.stream().collect(Collectors.toMap((prop) -> {
            Element element = (Element) prop;
            return element.attributeValue("name");
        }, (prop) -> {
            Element element = (Element) prop;
            return element.attributeValue("value");
        }));
        if (Const.UNPOOLED_DATASOURCE.equals(type.trim().toUpperCase())) {
            dataSource = new UnPooledDataSource(properties.get("driver"),
                    properties.get("username"), properties.get("password"), properties.get("url"));
        }

        return dataSource;
    }



}
